from sets import Set

from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.core import serializers
from django.db import models
from django.http import Http404, HttpResponse, HttpResponseNotAllowed

from models import APIKey


_MIMETYPE = {
    'json': 'application/json',
    'xml': 'application/xml'
}


def _key(request):
    return APIKey.objects.get(key=request.GET['key'])


def serialize(f):
    def wrapped(request, *args, **kwargs):
        format = request.GET.get('f', 'json')
        mimetype = _MIMETYPE.get(format, 'text/plain')
        try:
            result = f(request, *args, **kwargs)
        except ObjectDoesNotExist:
            response = HttpResponse('ERROR', mimetype=mimetype)
            response.status_code = 404
            return response
        if result:
            return HttpResponse(serializers.serialize(format, result), mimetype=mimetype)
        return HttpResponse('OK', mimetype=mimetype)
    return wrapped


@serialize
def index(request, app_label, model_name):
    model = models.get_model(app_label, model_name)
    return get_list_or_404(model)


@serialize
def add(request, app_label, model_name):
    if not _key(request).user.has_perm('%s.add_%s' % ((model_name,) * 2)):
        return HttpResponseForbidden()

    model = models.get_model(app_label, model_name)

    if request.method == 'POST':
        data = request.POST.copy()
        values = dict([(f.name, data.get(f.name, None)) for f in model._meta.fields])
        return [model.objects.create(**values)]

    raise HttpResponseNotAllowed()


@serialize
def delete(request, app_label, model_name, object_id):
    if not _key(request).user.has_perm('%s.delete_%s' % ((model_name,) * 2)):
        return HttpResponseForbidden()

    model = models.get_model(app_label, model_name)

    if request.method == 'POST':
        model.objects.get(pk=object_id).delete()
        return

    raise HttpResponseNotAllowed()


@serialize
def change(request, app_label, model_name, object_id):
    if not _key(request).user.has_perm('%s.change_%s' % ((model_name,) * 2)):
        return HttpResponseForbidden()

    model = models.get_model(app_label, model_name)
    original = model.objects.get(pk=object_id)

    if request.method == 'POST':
        data = request.POST.copy()
        keys = Set(data.keys()).intersection(Set([f.name for f in model._meta.fields]))
        for k in keys:
            setattr(original, k, data[k])
        original.save()
        return [original]

    return [original]


def existing(request, app_label, model_name, object_id):
    if request.method == 'POST':
        return change(request, app_label, model_name, object_id)
    if request.method == 'DELETE':
        return delete(request, app_label, model_name, object_id)


def otherwise(request, app_label, model_name):
    if request.method == 'PUT':
        return add(request, app_label, model_name)
    if request.method == 'GET':
        return index(request, app_label, model_name)